package org.fhnw.aigs.swingClient.GUI;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.LayoutStyle;
import javax.swing.SpinnerNumberModel;
import org.fhnw.aigs.commons.communication.IdentificationMessage;
import org.fhnw.aigs.swingClient.communication.Settings;
/**
* This class is responsible for the client settings.<br>
* This window is to manage the client settings. A user name, the identification, the
* server address and the server port can be defined. After a validation, the settings are stored
* throug the Setting class. The window can be called to any time when the program is running.
* Changes of the settings will be available after a restart or at the very first run of the program.<br>
* This class was originally named 'IdentificationGUI' and refactored to 'SettingsWindow' in v1.1<br>
* v1.0 Initial release<br>
* v1.1 Added funcionality and some fields<br>
* v1.2 Complete rewrite
* @author Matthias Stöckli (v1.0)
* @version 1.2 (Raphael Stoeckli, 14.10.2014)
*/
public class SettingsWindow extends JDialog {
/**
* Reference to the window
*/
private static SettingsWindow frame;
/**
* A checkbox to enable or diable loading this dialog at startup
*/
private JCheckBox startupCheckbox;
/**
* A checkbox to enable or diable the login
*/
private JCheckBox useLoginCheckbox;
/**
* A checkbox to enable or disable auto-connection to waiting games respectively auto-cration if no game is available
*/
private JCheckBox autoConnectCheckbox;
/**
* The Server Port
*/
private JSpinner portSpinner;
/**
* The Server URL or IP
*/
private JTextField serverAddressField;
/**
* The user name field.
*/
private JTextField usernameField;
/**
* The displayed name field of the user.
*/
private JTextField displaynameField;
/**
* The password field.
*/
private JTextField passwordField;
/**
* The user name or player field
*/
// private JLabel usernameLabel;
/**
* The cancel button
*/
private JButton cancelButton;
/**
* The save button
*/
private JButton saveButton;
/**
* Creates a new Setting window
*/
public SettingsWindow() {
this.setTitle("Settings");
this.setSize(466, 232);
this.setLocationByPlatform(true); // Better positioning of the window
this.setResizable(false);
init(); // Building the GUI
fillData(); // Fill presets
SettingsWindow.frame = this;
this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // validation will decide when to close
this.setAlwaysOnTop(true);
this.setModal(true);
this.addWindowListener(new SettingsWindow.CloseWindowAdapter());
}
/**
* Initializing the GUI. The lower part of this method was generated by NetBeans and cleaned up by hand
*/
private void init()
{
startupCheckbox = new JCheckBox("Open this dialog at client startup");
startupCheckbox.setToolTipText("If checked, this settings dialog will appear on every startup of the game");
autoConnectCheckbox = new JCheckBox("Automatically connect to a waiting game / Create new game automatically if none available");
autoConnectCheckbox.setToolTipText("<html>If checked, the client connects automatically to a waiting game if available on the server.<br>If no game is waiting, the client creates automatically a new waiting game</html>");
useLoginCheckbox = new JCheckBox("Use login on server");
useLoginCheckbox.setToolTipText("<html>If checked, the client sends username and password as identification to the server.<br>If not checked, the option of anonymous logon has to be enabled on the server. In this case, no password is required and the user name is only the display name</html> ");
useLoginCheckbox.addActionListener(new SettingsWindow.ToggleAnonymousLoginAction());
displaynameField = new JTextField();
displaynameField.setToolTipText("Name of the player (will be displayed in the game)");
usernameField = new JTextField();
usernameField.setToolTipText("Name of the player or user name (if login is enabled)");
passwordField = new JTextField();
passwordField.setToolTipText("Password of the user (if login is enabled)");
serverAddressField = new JTextField();
serverAddressField.setToolTipText("<html>A valid server address or IP like '127.0.0.1' or 'http://aigs.ch'.<br>Use 'localhost' when running an AIGS server on the same computer like the client</html>");
portSpinner = new JSpinner();
portSpinner.setToolTipText("<html>A valid port number from 1 to 65535.<br>The default value for AIGS is 25123</html>");
portSpinner.setModel(new SpinnerNumberModel(1, 1, 65535, 1));
portSpinner.setEditor(new JSpinner.NumberEditor(portSpinner, "#"));
saveButton = new JButton("Save and close");
saveButton.setToolTipText("Saves the settings and closes the dialog");
saveButton.addActionListener(new SettingsWindow.CheckAndCreateAction());
cancelButton = new JButton("Cancel");
cancelButton.setToolTipText("Discards the changes and closes the dialog");
cancelButton.addActionListener(new SettingsWindow.DiscardAction());
JLabel playerNameLabel = new JLabel("Player Name:");
JLabel usernameLabel = new JLabel("Login Name:");
JLabel passwordLabel = new JLabel("Password:");
JLabel serverAddressLabel = new JLabel("Server address:");
JLabel serverPortLabel = new JLabel("Server Port:");
GroupLayout layout = new GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(autoConnectCheckbox)
.addGroup(layout.createSequentialGroup()
.addComponent(startupCheckbox, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGap(245, 245, 245))
.addComponent(useLoginCheckbox)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
.addComponent(serverAddressLabel, GroupLayout.PREFERRED_SIZE, 97, GroupLayout.PREFERRED_SIZE)
.addComponent(passwordLabel, GroupLayout.Alignment.LEADING, GroupLayout.PREFERRED_SIZE, 97, GroupLayout.PREFERRED_SIZE))
.addComponent(serverPortLabel, GroupLayout.Alignment.LEADING, GroupLayout.PREFERRED_SIZE, 97, GroupLayout.PREFERRED_SIZE))
.addComponent(usernameLabel, GroupLayout.Alignment.LEADING, GroupLayout.PREFERRED_SIZE, 97, GroupLayout.PREFERRED_SIZE))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(usernameField, GroupLayout.DEFAULT_SIZE, 355, Short.MAX_VALUE)
.addComponent(passwordField)
.addComponent(serverAddressField)
.addGroup(layout.createSequentialGroup()
.addComponent(portSpinner, GroupLayout.PREFERRED_SIZE, 101, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(saveButton)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton))))
.addGroup(layout.createSequentialGroup()
.addComponent(playerNameLabel, GroupLayout.PREFERRED_SIZE, 97, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(displaynameField, GroupLayout.DEFAULT_SIZE, 355, Short.MAX_VALUE)))
.addContainerGap())
);
layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(startupCheckbox)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(autoConnectCheckbox)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useLoginCheckbox)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(displaynameField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(playerNameLabel))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(usernameField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(usernameLabel))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(passwordField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(passwordLabel))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(serverAddressField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(serverAddressLabel))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(serverPortLabel)
.addComponent(portSpinner, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addGap(0, 29, Short.MAX_VALUE))
.addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(saveButton)
.addComponent(cancelButton))
.addContainerGap())))
);
pack();
}
/**
* Handles close action. Shows a prompt which asks for confirmation.
*/
private static class CloseWindowAdapter extends WindowAdapter {
@Override
public void windowClosing(final WindowEvent e) {
HandleClosingAction(e.getComponent());
}
public static void HandleClosingAction(Component c)
{
if (Settings.getInstance().isInitialized() == false) // Only ask, if this is the very first start of the program, respectively if no settings file exists
{
int result = JOptionPane.showConfirmDialog(c,
"Are you sure you want to close the application?",
"Close the application?",
JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
System.exit(0);
}
}
else
{
SettingsWindow.frame.dispose(); // Close settings window
}
}
}
/**
* Closes the window without saving the settings
*/
private class DiscardAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
CloseWindowAdapter.HandleClosingAction(SettingsWindow.frame);
}
}
/**
* Enables or disables the identification code field depending on the
* check state of the anoymous login checkbox
*/
private class ToggleAnonymousLoginAction implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e) {
boolean checkState = useLoginCheckbox.isSelected();
if (checkState == false)
{
passwordField.setText("");
passwordField.setBackground(Color.LIGHT_GRAY);
passwordField.setEnabled(false);
usernameField.setText("");
usernameField.setBackground(Color.LIGHT_GRAY);
usernameField.setEnabled(false);
}
else
{
passwordField.setEnabled(true);
passwordField.setBackground(Color.WHITE);
usernameField.setEnabled(true);
usernameField.setBackground(Color.WHITE);
// usernameLabel.setText("Login name:");
}
}
}
/**
* Validates the content and saves through Setting class
* {@link IdentificationMessage}.
*/
private class CheckAndCreateAction implements ActionListener {
@Override
public void actionPerformed(final ActionEvent e) {
String playerName = displaynameField.getText().trim();
String userName = usernameField.getText().trim();
String password = passwordField.getText().trim();
String address = serverAddressField.getText().trim();
boolean useLogin = useLoginCheckbox.isSelected();
boolean autoConnect = autoConnectCheckbox.isSelected();
boolean showSettings = startupCheckbox.isSelected();
int port;
try
{
port = (int)portSpinner.getValue();
}
catch(Exception ex)
{
showMessage("Server port must be a integer between 1 and 65535","Invalid input");
return;
}
if (playerName.equals("")) {
showMessage("Player name not defined.","Invalid input");
return;
}
if (userName.equals("") && useLogin == true) {
showMessage("Login name not defined.","Invalid input");
return;
}
if (password.equals("") && useLogin == true) {
showMessage("Password not defined.","Invalid input");
return;
}
if (address.equals(""))
{
showMessage("Server address or IP not defined","Invalid input");
return;
}
if (port < 1 || port > 65535)
{
showMessage("Server port must be between 1 and 65535","Invalid input");
return;
}
// Creating the (not from server validated) user settings
if (Settings.getInstance().isInitialized() == true) // Existing Settings will be overwritten --> Message to user if game is running
{
if (Settings.getInstance().isGameRunning() == true)
{
showMessage("Changes of the user settings will only be applied after a restart of the client", "Settings changed");
}
}
if (useLogin == false)
{
password = "---"; // Default string (only for transmission, will not be checked, if anonymous login is enabled on the server)
userName = "User";
}
Settings.writeInstance(playerName, userName, password, address, port, useLogin, autoConnect, showSettings);
Settings.getInstance().saveSettings();
SettingsWindow.frame.dispose(); // Close window
}
}
/**
* Method to show a message box with an OK button
* @param message Message to show
* @param title Title of the message box
*/
private void showMessage(String message, String title)
{
JOptionPane.showMessageDialog(SettingsWindow.frame, message, title, JOptionPane.INFORMATION_MESSAGE);
}
/**
* Method fills existing settings information in the fields of the settings window, if existing
*/
private void fillData()
{
if (Settings.getInstance().isUsingLogin() == false)
{
useLoginCheckbox.setSelected(false);
passwordField.setText("");
passwordField.setBackground(Color.LIGHT_GRAY);
passwordField.setEnabled(false);
usernameField.setText("");
usernameField.setBackground(Color.LIGHT_GRAY);
usernameField.setEnabled(false);
}
else
{
useLoginCheckbox.setSelected(true);
passwordField.setText(Settings.getInstance().getPassword());
passwordField.setBackground(Color.WHITE);
passwordField.setEnabled(true);
usernameField.setText(Settings.getInstance().getUsername());
usernameField.setBackground(Color.WHITE);
usernameField.setEnabled(true);
}
startupCheckbox.setSelected(Settings.getInstance().getShowSettingsAtStartup());
autoConnectCheckbox.setSelected(Settings.getInstance().getAutoConnect());
displaynameField.setText(Settings.getInstance().getDisplayname());
serverAddressField.setText(Settings.getInstance().getServerAddress());
portSpinner.setValue(Settings.getInstance().getServerPort());
}
/**
* Shows the user that the identification was not successful.
*
* @param reason Text with the reason
*/
public static void notifyOfFailure(String reason) {
SettingsWindow.frame.showMessage(reason, "Error");
}
}